<template>
  <div class="flex flex-col gap-4">
    <div class="flex gap-2 items-center">
      <div class="w-20">模型名称</div>
      <el-input :disabled="info?.isDisabled" v-model="params.modelName" placeholder="请输入文件名"></el-input>
    </div>
    <div class="flex gap-2 items-center">
      <div class="w-20">备注</div>
      <el-input :disabled="info?.isDisabled" type="textarea" v-model="params.modelDesc" placeholder="请输入备注"></el-input>
    </div>
    <div class="flex gap-2 items-center">
      <div class="w-20">上传模型</div>
      <el-upload class="upload-demo" drag :limit="1" :before-upload="beforeUpload" accept=".zip" :http-request="uploadFile">
        <el-icon class="el-icon--upload"><upload-filled /></el-icon>
        <div class="el-upload__text">将文件放在此处或 <em>点击上传</em></div>
      </el-upload>
    </div>
    <!-- <div class="flex gap-2 items-center">
      <span>检测文件</span>
      <el-switch v-model="params.check"></el-switch>
      <span>开启检测之后可能会比较慢，请耐心等待</span>
    </div> -->
    <div class="flex gap-2 items-center">
      <span>上传进度</span>
      <el-progress :text-inside="true" :stroke-width="18" :percentage="percentage" class="flex-1"></el-progress>
    </div>
    <div class="flex justify-end gap-2">
      <el-button type="default" @click="onSuccess">取消</el-button>
      <el-button :loading="isLoading" type="primary" @click="handleUploadConfirm">确定</el-button>
    </div>
  </div>
</template>
<script setup lang="ts">
import { checkUploadProgressApi, initUpload, mergeFile, uploadChunkApi } from '@/api/bigfileupload'
import UseUpdate from '@/hooks/use-update'
import { ELocalStorageKey } from '@/types'
import { sessionStorage } from '@/utils/storage'
import * as zip from '@zip.js/zip.js'
import { message } from 'ant-design-vue'
import { IModel } from '../types/model'
const workspaceId: string = sessionStorage.get(ELocalStorageKey.WorkspaceId) || ''
interface Props {
  onSuccess: () => void
  info: IModel
}
// eslint-disable-next-line vue/no-setup-props-destructure
const { onSuccess, info } = defineProps<Props>()
const params = ref({
  modelName: info?.model_name || '',
  modelDesc: info?.model_desc || '',
  uploadId: info?.upload_id || '',
  shardCount: 0,
  // 是否开启检测
  check: false
})

// eslint-disable-next-line vue/no-setup-props-destructure
const fileData = ref<File | null>(null)
const uploadFile = () => {}
const isLoading = ref(false)
const breakpoint = ref(0)
const validateB3DMFile = (filebuffer) => {
  return new Promise((resolve, reject) => {
    try {
      const magicNumber = String.fromCharCode(...filebuffer.subarray(0, 4))
      if (magicNumber !== 'b3dm') {
        resolve(false)
      }
      resolve(true)
    } catch (error) {
      console.error('验证 .b3dm 文件时出错:', error)
      resolve(false)
    }
  })
}
function extractZip(file: File) {
  // eslint-disable-next-line no-async-promise-executor
  return new Promise(async (resolve, reject) => {
    const zipFileReader = new zip.BlobReader(file)
    const zipReader = new zip.ZipReader(zipFileReader)
    const ls = new Map()
    // 获取 ZIP 文件中的所有条目
    const entries = await zipReader.getEntries()
    const data = entries.find((entry) => {
      return entry.filename === 'tileset.json'
    })
    if (!data) {
      zipReader.close()
      reject(new Error('缺少tileset.json'))
      return
    }
    for (const entry of entries) {
      if (entry.filename.includes('/')) {
        zipReader.close()
        reject(new Error('嵌套文件检测到'))
        return
      }
      // 检测当前文件名称只能是 .b3dm或者.json
      if (!entry.filename.endsWith('.b3dm') && !entry.filename.endsWith('.json') && !entry.filename.endsWith('.cmpt')) {
        zipReader.close()
        reject(new Error('文件格式错误'))
        return
      }
      // if (params.value.check && entry.filename.endsWith('.b3dm')) {
      //   // 读取条目内容
      //   const entryContent = await entry.getData(new zip.BlobWriter('application/octet-stream'))
      //   const filebuffer = new Uint8Array(await entryContent.arrayBuffer())
      //   // 验证 .b3dm 文件
      //   const data = await validateB3DMFile(filebuffer)
      //   if (!data) {
      //     zipReader.close()
      //     reject(new Error('文件格式错误'))
      //     console.log('当前文件名不是 .b3dm 或者 .json 格式')
      //     return
      //   }
      //   ls.set(entry.filename, data)
      //   console.log(data, 'data-----------------------')
      // }
      resolve(true)
    }
  })
}

const beforeUpload = async (file: File) => {
  try {
    // 调用 extractZip 并捕获异常
    await extractZip(file)
  } catch (error: { message: string }) {
    if (error.message === '嵌套文件检测到') {
      message.error('检测到嵌套文件，请检查文件格式后重试')
      return false // 阻止上传
    }
    if (error.message === '文件格式错误') {
      message.error('文件格式错误，请检查文件格式后重试')
      return false // 阻止上传
    }

    if (error.message === '缺少tileset.json') {
      message.error('缺少tileset.json，请检查文件格式后重试')
      return false // 阻止上传
    }
    // 其他错误处理逻辑
    return false
  }
  if (!info) {
    fileData.value = file
    return true
  } else {
    // 先判断两个文件的名称
    if (file.name !== info.file_name) {
      message.error('请选择相同的文件进行上传')
      return false
    }
    // 首先计算两个是否是一个文件
    const { code, data } = await checkUploadProgressApi(info.upload_id)
    const isSame = await UseUpdate.isSameTask(file, data.partETags)
    if (!isSame) {
      message.error('请选择相同的文件进行上传')
      return false
    }
    // 计算从第几个点开始进行切片上传
    breakpoint.value = data.partETags.length
    fileData.value = file
  }
}

const uploaded = ref(0)
const chunkId = ref(0)
const handleUploadConfirm = async () => {
  // 先检测是否是断点上传
  if (!info) {
    if (params.value.modelName.trim() === '' || params.value.modelDesc.trim() === '') {
      message.info('请填写文件名和备注')
      return
    }
    if (fileData.value === null) {
      message.info('请选择文件')
      return
    }
    const name = fileData.value.name
    params.value.shardCount = UseUpdate.getShardCount(fileData.value!)
    uploaded.value = 0
    isLoading.value = true
    initUpload({
      fileName: name,
      modelName: params.value.modelName,
      modelDesc: params.value.modelDesc,
      workspaceId: workspaceId
    }).then((response) => {
      if (response.code === 1) {
        message.info('上传中...请不需要操作')
        params.value.uploadId = response.data.uploadId
        uploadByChunk(chunkId.value)
      } else {
        console.error(response.msg)
      }
    })
  } else {
    params.value.shardCount = UseUpdate.getShardCount(fileData.value!)
    if (breakpoint.value === params.value.shardCount) {
      mergeFile(params.value.uploadId).then((response) => {
        if (response.code === 1) {
          isLoading.value = false
          onSuccess()
        } else {
          console.error(response.msg, '删除失败')
        }
      })
      return
    }
    chunkId.value = breakpoint.value
    uploaded.value = breakpoint.value
    isLoading.value = true
    uploadByChunk(chunkId.value)
  }
}

const uploadByChunk = async (index: number) => {
  const { file } = await UseUpdate.getChunkFile(fileData.value!, index)
  const form = UseUpdate.createChunkFormData(file, params.value.uploadId, index + 1, params.value.shardCount)
  uploadChunkApi(form).then((response) => {
    if (response.code === 1) {
      if (UseUpdate.readMd5(index) === response.data.md5Str) {
        uploaded.value++
        const percent = Math.floor((uploaded.value / params.value.shardCount) * 100)
        percentageSend(percent)
        index++
        if (index < params.value.shardCount) {
          uploadByChunk(index)
        }
      } else {
        uploadByChunk(index)
      }
    } else {
      console.error(response.msg)
    }
  })
}
const percentage = ref(0)
const percentageSend = (perNum: number) => {
  percentage.value = perNum
  if (perNum === 100) {
    mergeFile(params.value.uploadId).then((response) => {
      if (response.code === 1) {
        isLoading.value = false
        onSuccess()
      } else {
        console.error(response.msg, '删除失败')
      }
    })
  }
}
</script>

<style></style>
